#include<iostream>
#include<vector>
#include<cstdint>
#include<iomanip>
#include<stdlib.h>
#include<fstream>
#include<stack>

#ifdef _WIN32
#include<windows.h>
#else
#include<unistd.h>
#endif

using namespace std;
using uint = unsigned int;
enum {
	NOP=0x00,
	PUSH,
	POP,
	DUP,
	SWAP,
	DUP2,
	SWAP2,
	ADD,//+
	SUB,//-
	MUL,//*
	DIV,// /
	MOD,//%
	JMP,//jump
	JMPS,//jump in stack
	BIZ,//Branch If Zero
	BIZS,//Branch If Zero in stack
	BNZ,//Branch if Not zero
	EQ,//==
	NE,//!=
	GT,//>
	LT,//<
	GE,//>=
	LE,//<=
	Bang,//!
	DBang,//!!
	NOT,//~
	OR,//|
	AND,//&
	XOR,//^
	TRAP,//trap
	LD,//load
	ST,//store
	LDS,//load in stack
	STS,//store in stack
	JSS,//jump store stack(f)
	JSSS,//jump store stack(f) in stack(v)
	RET,//ret
};

enum {
	DIV0=0x01,
	MOD0,
	
};

class undererr{
	
};
class Estack{
	stack<int> v;
	public:
		void push(const int &x){
			v.push(x);
		}
		int pop(){
			if(v.empty()){
				throw undererr();
			}
			int a=v.top();
			v.pop();
			return a;
		}
		int top(){
			if(v.empty()){
				throw undererr();
			}
			return v.top();
		}
		int top2(){
			if(v.size()<2){
				throw undererr();
			}
			int a=v.top();
			v.pop();
			int b=v.top();
			v.push(a);
			return b;
		}
		bool empty(){
			return v.empty();
		}
};

vector<uint> memory(16777215);//2^24-1
//faq:
//q:why not use 2^16-1 or 2^32-1
//a:because 2^16-1 is too little and 2^32-1 is too big

class ECore{
	Estack vstack,fstackl,tstack;
	int errcode;
	public:
		void run(){
			for(int post=0;post<16777215;){
				try{
				switch(memory[post]){
					case NOP:{
						post++;
						break;
					}
					case PUSH:
						vstack.push(memory[++post]);
						post++;
						break;
					case POP:
						vstack.pop();post++;
						break;
					case DUP:{
						vstack.push(vstack.top());post++;
						break;
					}
					case SWAP:{
						int a=vstack.top();vstack.pop();
						int b=vstack.top();vstack.pop();
						vstack.push(a);
						vstack.push(b);post++;
						break;
					}
					case DUP2:{
						int a=vstack.top();vstack.pop();
						int b=vstack.top();vstack.pop();
						vstack.push(b);
						vstack.push(a);
						vstack.push(b);post++;
						break;
					}
					case SWAP2:{
						int a=vstack.top();vstack.pop();
						int b=vstack.top();vstack.pop();
						int c=vstack.top();vstack.pop();
						vstack.push(a);
						vstack.push(b);
						vstack.push(c);post++;
						break;
					}
					case ADD:{
					    int b=vstack.top();vstack.pop();
					    int a=vstack.top();vstack.pop();
					    vstack.push(a+b);
					    post++;
					    break;
					}
					case SUB:{
					    int b = vstack.top(); vstack.pop();
					    int a = vstack.top(); vstack.pop();
					    vstack.push(a-b);
					    post++;
					    break;
					}
					case MUL:{
					    int b = vstack.top(); vstack.pop();
					    int a = vstack.top(); vstack.pop();
					    vstack.push(a * b);
					    post++;
					    break;
					}
					case DIV:{
					    int b = vstack.top(); vstack.pop();
					    int a = vstack.top(); vstack.pop();
					    if(b==0){
					    	if(tstack.empty()){
					    		cout<<"runtime error: DIV by zero\n";
							}else{
								post=tstack.top();
								errcode=DIV0;
								continue;
							}
					    } else {
					        vstack.push(a / b);
					    }
					    post++;
					    break;
					}
					case MOD:{
					    int b = vstack.top(); vstack.pop();
					    int a = vstack.top(); vstack.pop();
					    if(b==0){
					    	if(tstack.empty()){
					    		cout<<"runtime error: MOD by zero\n";
							}else{
								post=tstack.top();
								errcode=MOD0;
								continue;
							}
					    } else {
					        vstack.push(a%b);
					    }
					    post++;
					    break;
					}
					case JMP:{
						post=memory[++post];
						break;
					}
					case JMPS:{
						post=vstack.top();
						vstack.pop();
						break;
					}
					case BIZ:{
						if(vstack.top()){
							++post;++post;
						}else{
							post=memory[++post];
						}
						vstack.pop();
						break;
					}
					case BIZS:{
						if(vstack.top2()){
							++post;
						}else{
							post=vstack.top();
						}
						vstack.pop();
						vstack.pop();
						break;
					}
					case BNZ:{
						if(vstack.top()){
							post=memory[++post];
						}else{
							++post;++post;
						}
						vstack.pop();
						break;
					}
				}
				}catch(undererr &){
					please add stack error catch
				}
			}
		}
};

int main(int ac,char **av){
	cout<<"EVM 0.1.0 ...";
	if(ac==1){
		cout<<"\nWelome to use EVM!\n";
		return 0;
	}
	cout<<"\r                  \r";
}